/* 
 * Copyright (C) 2014 Krzysztof Troska <elleander86 at gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package anidbjclient;

import java.awt.Desktop;
import java.awt.Image;
import java.io.IOException;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

/**
 *
 * @author Krzysztof Troska <elleander86 at gmail.com>
 */
public class AnidbJClientGUI extends javax.swing.JFrame {
    /**
     * Database connection - main connection used throught whole app.
     */
    public static final Database DB = new Database();
    
    /**
     * Creates config manager which loads standard config.
     */
    public static final ConfigManager cm = new ConfigManager();
    
    /**
     * Creates new form AnidbJClientGUI
     */
    public AnidbJClientGUI() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jMenu5 = new javax.swing.JMenu();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        animeList = new javax.swing.JTable();
        searchField = new javax.swing.JTextField();
        searchButton = new javax.swing.JButton();
        animePic = new javax.swing.JLabel();
        animeNameLabel = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        episodesList = new javax.swing.JTable();
        jScrollPane4 = new javax.swing.JScrollPane();
        descriptionArea = new javax.swing.JTextPane();
        playButton = new javax.swing.JButton();
        prewievButton = new javax.swing.JButton();
        markWatchedButton = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        userName = new javax.swing.JTextField();
        userPassword = new javax.swing.JPasswordField();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        downloadPathField = new javax.swing.JTextField();
        animePathField = new javax.swing.JTextField();
        downloadButton = new javax.swing.JButton();
        animeButton = new javax.swing.JButton();
        jButton1 = new javax.swing.JButton();
        jLabel6 = new javax.swing.JLabel();
        jLabel7 = new javax.swing.JLabel();
        jLabel8 = new javax.swing.JLabel();
        anidbServer = new javax.swing.JTextField();
        anidbPort = new javax.swing.JTextField();
        localPort = new javax.swing.JTextField();
        stopDaemonButton = new javax.swing.JButton();
        startDaemonButton = new javax.swing.JButton();
        checkDaemonButton = new javax.swing.JButton();
        jMenuBar2 = new javax.swing.JMenuBar();
        jMenu3 = new javax.swing.JMenu();
        addFilesMenu = new javax.swing.JMenuItem();
        repairDatabase = new javax.swing.JMenuItem();
        jMenu4 = new javax.swing.JMenu();

        jMenu5.setText("jMenu5");

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setResizable(false);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        animeList.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "aid", "Name", "Episodes", "Owned Ep"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.Integer.class, java.lang.String.class, java.lang.Integer.class, java.lang.Integer.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        animeList.setRowHeight(20);
        animeList.getSelectionModel().addListSelectionListener(new AnimeListListener());
        animeList.getColumnModel().getColumn(0).setMinWidth(0);
        animeList.getColumnModel().getColumn(0).setMaxWidth(0);
        animeList.getColumnModel().getColumn(0).setWidth(0);
        jScrollPane1.setViewportView(animeList);

        searchButton.setText("Search");
        searchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                searchButtonActionPerformed(evt);
            }
        });

        animePic.setMaximumSize(new java.awt.Dimension(283, 296));
        animePic.setMinimumSize(new java.awt.Dimension(283, 296));

        animeNameLabel.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        animeNameLabel.setText("Anime Name");

        episodesList.setBackground(new java.awt.Color(240, 240, 240));
        episodesList.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "eid", "Episode nr", "Episode"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.Integer.class, java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        episodesList.setRowHeight(20);
        episodesList.getColumnModel().getColumn(0).setMinWidth(0);
        episodesList.getColumnModel().getColumn(0).setMaxWidth(0);
        episodesList.getColumnModel().getColumn(0).setWidth(0);
        jScrollPane2.setViewportView(episodesList);
        if (episodesList.getColumnModel().getColumnCount() > 0) {
            episodesList.getColumnModel().getColumn(1).setPreferredWidth(2);
        }

        descriptionArea.setContentType("text/html"); // NOI18N
        jScrollPane4.setViewportView(descriptionArea);

        playButton.setText("Play");
        playButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                playButtonActionPerformed(evt);
            }
        });

        prewievButton.setText("Prewiev");
        prewievButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                prewievButtonActionPerformed(evt);
            }
        });

        markWatchedButton.setText("Mark Watched");
        markWatchedButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                markWatchedButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(searchField, javax.swing.GroupLayout.PREFERRED_SIZE, 213, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(searchButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 300, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(animeNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 516, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(animePic, javax.swing.GroupLayout.PREFERRED_SIZE, 270, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel2Layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 242, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addGroup(jPanel2Layout.createSequentialGroup()
                                        .addComponent(prewievButton, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(markWatchedButton, javax.swing.GroupLayout.PREFERRED_SIZE, 118, javax.swing.GroupLayout.PREFERRED_SIZE))))
                            .addGroup(jPanel2Layout.createSequentialGroup()
                                .addGap(71, 71, 71)
                                .addComponent(playButton, javax.swing.GroupLayout.PREFERRED_SIZE, 113, javax.swing.GroupLayout.PREFERRED_SIZE)))))
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGap(0, 0, 0)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(animeNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(searchField, javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(searchButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addGroup(jPanel2Layout.createSequentialGroup()
                                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 237, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                    .addComponent(markWatchedButton)
                                    .addComponent(prewievButton))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(playButton))
                            .addComponent(animePic, javax.swing.GroupLayout.DEFAULT_SIZE, 296, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jScrollPane4))
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 493, Short.MAX_VALUE)))
        );

        jPanel2Layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {markWatchedButton, playButton, prewievButton});

        jTabbedPane1.addTab("Anime", jPanel2);

        jLabel1.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel1.setText("Options:");

        jLabel2.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel2.setText("User Name:");

        jLabel3.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel3.setText("Password:");

        userName.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N

        userPassword.setText(cm.getPassword());
        userPassword.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N

        jLabel4.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel4.setText("Download:");

        jLabel5.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel5.setText("Video:");

        downloadPathField.setText(cm.getDownloadPath().toString());
        downloadPathField.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N

        animePathField.setText(cm.getAnimePath().toString());
        animePathField.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N

        downloadButton.setText("Select....");
        downloadButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                downloadButtonActionPerformed(evt);
            }
        });

        animeButton.setText("Select...");
        animeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                animeButtonActionPerformed(evt);
            }
        });

        jButton1.setText("Save");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jLabel6.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel6.setText("AniDB Server:");

        jLabel7.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel7.setText("AniDB Port:");

        jLabel8.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel8.setText("Local Port:");

        anidbServer.setText(cm.getServerName());
        anidbServer.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N

        anidbPort.setText(Integer.toString(cm.getPort()));
        anidbPort.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N

        localPort.setText(Integer.toString(cm.getLocalPort()));
        localPort.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N

        stopDaemonButton.setText("Stop Daemon");
        stopDaemonButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopDaemonButtonActionPerformed(evt);
            }
        });

        startDaemonButton.setText("Start Daemon");
        startDaemonButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startDaemonButtonActionPerformed(evt);
            }
        });

        checkDaemonButton.setText("Check Daemon");
        checkDaemonButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                checkDaemonButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(jPanel1Layout.createSequentialGroup()
                                        .addContainerGap()
                                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addComponent(jLabel4)
                                            .addComponent(jLabel2)
                                            .addComponent(jLabel3)))
                                    .addGroup(jPanel1Layout.createSequentialGroup()
                                        .addGap(10, 10, 10)
                                        .addComponent(jLabel5)))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(userName, javax.swing.GroupLayout.PREFERRED_SIZE, 170, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(animePathField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(userPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addComponent(downloadPathField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                                    .addComponent(jLabel8)
                                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addComponent(jLabel7)
                                        .addComponent(jLabel6)))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                    .addComponent(checkDaemonButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                        .addComponent(startDaemonButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(stopDaemonButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(jButton1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(anidbServer)
                                        .addComponent(anidbPort)
                                        .addComponent(localPort)))))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(animeButton)))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(10, 10, 10)
                        .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 137, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(399, Short.MAX_VALUE))
        );

        jPanel1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {anidbPort, anidbServer, animePathField, downloadPathField, jLabel1, jLabel2, jLabel3, jLabel4, jLabel5, jLabel6, jLabel7, jLabel8, localPort, userName, userPassword});

        jPanel1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {animeButton, downloadButton});

        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel2)
                    .addComponent(userName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel3)
                    .addComponent(userPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(8, 8, 8)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel4)
                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(downloadPathField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(downloadButton)))
                .addGap(6, 6, 6)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel5)
                    .addComponent(animePathField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(animeButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel6)
                    .addComponent(anidbServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel7)
                    .addComponent(anidbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel8)
                    .addComponent(localPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(stopDaemonButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(startDaemonButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(checkDaemonButton)
                .addContainerGap(153, Short.MAX_VALUE))
        );

        jPanel1Layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {anidbPort, anidbServer, animeButton, animePathField, downloadButton, downloadPathField, jButton1, jLabel1, jLabel2, jLabel3, jLabel4, jLabel5, jLabel6, jLabel7, jLabel8, localPort, userName, userPassword});

        userName.setText(cm.getUserName());

        jTabbedPane1.addTab("Options", jPanel1);

        jMenu3.setText("File");

        addFilesMenu.setText("Add Files");
        addFilesMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addFilesMenuActionPerformed(evt);
            }
        });
        jMenu3.add(addFilesMenu);

        repairDatabase.setText("Repair Database");
        repairDatabase.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                repairDatabaseActionPerformed(evt);
            }
        });
        jMenu3.add(repairDatabase);

        jMenuBar2.add(jMenu3);

        jMenu4.setText("Edit");
        jMenuBar2.add(jMenu4);

        setJMenuBar(jMenuBar2);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    private void addFilesMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addFilesMenuActionPerformed
        AnidbInserter.threads.stream().filter((thread) -> (!thread.isInterrupted())).forEach((thread) -> {
            thread.interrupt();
        });
    }//GEN-LAST:event_addFilesMenuActionPerformed

    private void repairDatabaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_repairDatabaseActionPerformed
       System.err.println("Repair Database: " + DB.repairDatabase());
    }//GEN-LAST:event_repairDatabaseActionPerformed

    private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
        String name = searchField.getText();
        Map<String, List<Object>> map;
        String[] columns = {"anime.aid AS aid", "anime.name AS name", "anime.episodes AS episodes",
            /** We create new colum  not_watched which have 1 if there is at least 1 episode which is not marked as watched.*/
            "CASE WHEN anime.aid IN (SELECT anime.aid FROM anime, files, my_list WHERE anime.aid = files.aid AND files.fid "
            + "= my_list.fid GROUP BY anime.name HAVING viewed_date = -1) THEN 1 ELSE 0 END AS not_watched",
            "COUNT(*) AS owned_episodes"};
        StringBuilder sb = new StringBuilder();
        sb.append("episodes, anime, files WHERE anime.aid = episodes.aid AND "
                + "episodes.eid = files.eid ");
        if(!name.isEmpty()) {
            sb.append("AND anime.name LIKE '%");
            sb.append(name.replaceAll("'", "''"));
            sb.append("%'");
        }
        sb.append(" GROUP BY anime.aid ORDER BY anime.air_date DESC");
        map = DB.getDatabaseInfo(columns, sb.toString());
        DefaultTableModel animeListModel = (DefaultTableModel) animeList.getModel();
        animeListModel.setRowCount(0);
        try {
            int size = map.get("aid").size();
            for(int i=0; i<size; i++) {
                String animeName;
                if((boolean)map.get("not_watched").get(i))
                    animeName = "<html><b>" + map.get("name").get(i) + "</b></html>";
                else
                    animeName = map.get("name").get(i).toString();
                Object[] row = new Object[4];
                row[0] = map.get("aid").get(i);
                row[1] = animeName;
                row[2] = map.get("episodes").get(i);
                row[3] = map.get("owned_episodes").get(i);
                animeListModel.addRow(row);
            }
        } catch (NullPointerException e) {
            System.err.println("No anime found.");
        }
    }//GEN-LAST:event_searchButtonActionPerformed

    private void downloadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed
        JFileChooser fc = new JFileChooser();
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fc.setCurrentDirectory(cm.getDownloadPath().toFile());
        int returnValue = fc.showOpenDialog(jLabel1);
        if(returnValue == JFileChooser.APPROVE_OPTION) {
            Path path = fc.getSelectedFile().toPath();
            downloadPathField.setText(path.toString());
            cm.setDownloadPath(path);
        }
        else
            System.err.println("No Directory selected.");
    }//GEN-LAST:event_downloadButtonActionPerformed

    private void animeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_animeButtonActionPerformed
        JFileChooser fc = new JFileChooser();
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fc.setCurrentDirectory(cm.getAnimePath().toFile());
        int returnValue = fc.showOpenDialog(jLabel1);
        if(returnValue == JFileChooser.APPROVE_OPTION) {
            Path path = fc.getSelectedFile().toPath();
            animePathField.setText(path.toString());
            cm.setAnimePath(path);
        }
        else
            System.err.println("No Directory selected.");
    }//GEN-LAST:event_animeButtonActionPerformed

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        try {
            cm.setAnimePath(Paths.get(animePathField.getText()));
        } catch(InvalidPathException e) {
            System.err.println("Invalid path Exception in get anime path");
        }
        try {
            cm.setDownloadPath(Paths.get(downloadPathField.getText()));
        } catch(InvalidPathException e) {
            System.err.println("Invalid path Exception in get download path");
        }
        cm.setLocalPort(Integer.parseInt(localPort.getText()));
        cm.setPort(Integer.parseInt(anidbPort.getText()));
        cm.setUserName(userName.getText());
        cm.setPassword(userPassword.getPassword());
        cm.saveConfigToFile();
    }//GEN-LAST:event_jButton1ActionPerformed

    private void prewievButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prewievButtonActionPerformed
        playFile(true, false);
    }//GEN-LAST:event_prewievButtonActionPerformed

    private void markWatchedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_markWatchedButtonActionPerformed
        playFile(false, true);
    }//GEN-LAST:event_markWatchedButtonActionPerformed

    private void playButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playButtonActionPerformed
        playFile(true, true);
    }//GEN-LAST:event_playButtonActionPerformed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        AnidbInserter.cancel();
        AnidbInserter.threads.stream().filter((thread) -> (thread.isAlive())).map((thread) -> {
            thread.interrupt();
            return thread;
        }).forEach((thread) -> {
            try {
                thread.join(500);
            } catch (InterruptedException ex) {
                System.err.println("InterruptedException on windowClosing.");
            }
        });
        System.out.println("Good Bye");
    }//GEN-LAST:event_formWindowClosing

    private void stopDaemonButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopDaemonButtonActionPerformed
        AnidbInserter.cancel();
        AnidbInserter.threads.stream().filter((thread) -> (!thread.isInterrupted())).forEach((thread) -> {
            thread.interrupt();
        });
    }//GEN-LAST:event_stopDaemonButtonActionPerformed

    private void startDaemonButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startDaemonButtonActionPerformed
        Thread inserter = new Thread(new AnidbInserter());
        inserter.setDaemon(true);
        inserter.start();
    }//GEN-LAST:event_startDaemonButtonActionPerformed

    private void checkDaemonButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkDaemonButtonActionPerformed
        AnidbInserter.threads.stream().filter((thread) -> (thread.isAlive())).forEach((thread) -> {
            System.out.println(thread);
        });
    }//GEN-LAST:event_checkDaemonButtonActionPerformed
    
    /**
     * Function to play or mark file watched or for both of them
     * @param play - true if we want to play file
     * @param markWatched - true if we want to mark file watched
     */
    private void playFile(final boolean play, final boolean markWatched) {
        int eid;
        try {
            eid = (int)episodesList.getValueAt(episodesList.getSelectedRow(), 0);
        } catch (ArrayIndexOutOfBoundsException ex) {
            // TODO: show information that no item selected
            return; //no or bad select no play
        }
        List<Object[]> list = DB.getEpisodePath(eid);
        if(list == null)
            return; // TODO: show database error
        if(list.size() > 1)
            return; // TODO: make a choise selecting option
        if(markWatched)
            DB.markWatched((int)list.get(0)[0]);
        if(play)
            try {
                Desktop.getDesktop().open(Paths.get(list.get(0)[1].toString()).toFile());
            } catch (IOException ex) {
                System.err.println("Can't play file");
            }
    }
    
    /**
     * Listener for selection change in animeList - show informations about selected anime on right side
     */
    private class AnimeListListener implements ListSelectionListener {
    @Override
    public void valueChanged(ListSelectionEvent e) {
        int aid;
        String name;
        try {
            aid = (int)animeList.getValueAt(animeList.getSelectedRow(), 0);
            name = animeList.getValueAt(animeList.getSelectedRow(), 1).toString();
        } catch(ArrayIndexOutOfBoundsException ex) {
            return; // no selects 
        }
        /** Name */
        animeNameLabel.setText("<html><b>"+name+"</b></html>");
        
        /** Before connection to anidb*/
        descriptionArea.setText("Getting description from anidb... Please Wait");
        
        /** Episode List */
        Map<String, List<Object>> list = DB.getEpisodeInfo(aid);
        DefaultTableModel episodesListModel = (DefaultTableModel) episodesList.getModel();
        episodesListModel.setRowCount(0);
        if(list != null) {
            Map<String, List<Object>> map;
            map = DB.getEpisodeInfo(aid);
            try {
                int size = map.get("eid").size();
                int type = 1;
                for(int i=0; i<size; i++) {       
                    String episodeName;
                    if(type != (int)map.get("type").get(i)) {
                        type = (int)map.get("type").get(i);
                        Object[] row = {"", "", DB.getSpecialString(type)};
                        episodesListModel.addRow(row);
                        i--;
                        continue;
                    }
                    if(!map.get("ep_name_en").get(i).toString().isEmpty())
                        episodeName = map.get("ep_name_en").get(i).toString();
                    else if(!map.get("ep_name").get(i).toString().isEmpty())
                        episodeName = map.get("ep_name").get(i).toString();
                    else
                        episodeName = "Episode " + map.get("ep_number").get(i);
                    if((int)map.get("viewed_date").get(i) <=0)
                        episodeName = "<html><b>" + episodeName + "</html></b>";
                    Object[] row = {map.get("eid").get(i), map.get("ep_number").get(i), episodeName};
                    episodesListModel.addRow(row);
                }
            } catch (NullPointerException ex) {
                System.err.println("No anime found.");
            }
        }
        
        /** Anime Pic */
        Path path = DB.getAnimePic(aid);
        ImageIcon icon;
        if(path != null) {
            icon = new ImageIcon(path.toString());
            Image img = icon.getImage();
            float imageHeight = img.getHeight(animePic);
            float imageWidth = img.getWidth(animePic);
            float animePicHeight = animePic.getHeight();
            float proportion = imageHeight/animePicHeight;
            Image newimg = img.getScaledInstance((int)(imageWidth/proportion), (int)animePicHeight,  java.awt.Image.SCALE_SMOOTH); 
            icon = new ImageIcon(newimg); 
            animePic.setIcon(icon);
            //Generaly not needed yet.
            //animePic.setMaximumSize(new java.awt.Dimension((int)(imageWidth/proportion), (int)animePicHeight));
        } // TODO: for some reason we did not get pic 
        
        /** Description */
        String desc = DB.getAnimeDescription(aid);
        //desc = desc.replaceAll("[","<");
        //desc = desc.replaceAll("]",">");
        descriptionArea.setText(desc);
    }
}
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(AnidbJClientGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(() -> {
            new AnidbJClientGUI().setVisible(true);
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem addFilesMenu;
    private javax.swing.JTextField anidbPort;
    private javax.swing.JTextField anidbServer;
    private javax.swing.JButton animeButton;
    private javax.swing.JTable animeList;
    private javax.swing.JLabel animeNameLabel;
    private javax.swing.JTextField animePathField;
    private javax.swing.JLabel animePic;
    private javax.swing.JButton checkDaemonButton;
    private javax.swing.JTextPane descriptionArea;
    private javax.swing.JButton downloadButton;
    private javax.swing.JTextField downloadPathField;
    private javax.swing.JTable episodesList;
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JMenu jMenu4;
    private javax.swing.JMenu jMenu5;
    private javax.swing.JMenuBar jMenuBar2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JTextField localPort;
    private javax.swing.JButton markWatchedButton;
    private javax.swing.JButton playButton;
    private javax.swing.JButton prewievButton;
    private javax.swing.JMenuItem repairDatabase;
    private javax.swing.JButton searchButton;
    private javax.swing.JTextField searchField;
    private javax.swing.JButton startDaemonButton;
    private javax.swing.JButton stopDaemonButton;
    private javax.swing.JTextField userName;
    private javax.swing.JPasswordField userPassword;
    // End of variables declaration//GEN-END:variables
}
